﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Loki.Utils
{
    public class SettingsConfiguration
    {
        public string Key
        {
            get;
            private set;
        }

        private ISet<string> _Properties;

        public IEnumerable<string> Properties
        {
            get { return _Properties; }
        }

        public WeakReference TargetReference
        {
            get;
            private set;
        }

        public SettingsConfiguration(object P_Target)
        {
            this.TargetReference = new WeakReference(P_Target);
            _Properties = new HashSet<string>();
        }

        /// <summary>
        /// Creates a configuration with all public properties.
        /// </summary>
        /// <returns>Settings configuration.</returns>
        public SettingsConfiguration AddMetaData()
        {
            // add properties that need to be tracked
            foreach (PropertyInfo L_Info in TargetReference.Target.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (L_Info.CanRead && L_Info.CanWrite)
                {
                    AddProperties(L_Info.Name);
                }
            }

            return this;
        }

        private SettingsConfiguration AddProperties(params string[] P_Properties)
        {
            foreach (string L_Properties in P_Properties)
            {
                _Properties.Add(L_Properties);
            }

            return this;
        }

        public SettingsConfiguration AddProperties<T>(params Expression<Func<T, object>>[] P_Properties)
        {
            AddProperties(P_Properties.Select(x => ExpressionHelper.GetMember(x).Name).ToArray());
            return this;
        }

        private SettingsConfiguration RemoveProperties(params string[] P_Properties)
        {
            foreach (string L_Properties in P_Properties)
            {
                _Properties.Remove(L_Properties);
            }

            return this;
        }

        public SettingsConfiguration RemoveProperties<T>(params Expression<Func<T, object>>[] P_Properties)
        {
            RemoveProperties(P_Properties.Select(x => ExpressionHelper.GetMember(x).Name).ToArray());
            return this;
        }

        public SettingsConfiguration SetKey(string P_Key)
        {
            this.Key = P_Key;
            return this;
        }
    }
}
